package system

import (
	"encoding/json"
	amqp "github.com/rabbitmq/amqp091-go"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"log"
	"process/global"
	"process/model/system"
	"time"
)

type StudentProcess struct{}

func (st *StudentProcess) RecordStudentClasses() {
	conn, err := RabbitMQService.GetConnection()
	if err != nil {
		global.GVA_LOG.Info("Failed to connect to RabbitMQ", zap.Error(err))
		return
	}
	defer conn.Close()
	ch, err := conn.Channel()
	if err != nil {
		global.GVA_LOG.Info("recordStudentClasses Failed to open a channel", zap.Error(err))
		return
	}
	defer ch.Close()

	//如果queue不存在则声明
	q, err := ch.QueueDeclare(
		"delayed_queue", // name
		true,            // durable
		false,           // delete when unused
		false,           // exclusive
		false,           // no-wait
		nil,             // arguments
	)
	if err != nil {
		global.GVA_LOG.Info("recordStudentClasses Failed to declare a queue", zap.Error(err))
		return
	}

	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto ack
		false,  // exclusive
		false,  // no local
		false,  // no wait
		nil,    // args
	)
	if err != nil {
		global.GVA_LOG.Info("recordStudentClasses Failed to register a consumer", zap.Error(err))
		return
	}

	forever := make(chan bool)
	go func() {
		for d := range msgs {
			log.Printf(" 接受到延迟消息 %s", d.Body)
			type message struct {
				StudentID  int64   `json:"student_id"`
				CourseID   int64   `json:"course_id"`
				ClassCount float64 `json:"class_count"`
			}
			var m message
			err = json.Unmarshal(d.Body, &m)
			if err != nil {
				global.GVA_LOG.Error("扣除学生课时json解析失败", zap.Any("receiverMessage", m))
				continue
			}
			var teacherCourse system.TeacherCourse
			err = global.GVA_DB.Where("course_id=?", m.CourseID).Preload("Classroom").First(&teacherCourse).Error

			if err != nil {
				global.GVA_LOG.Error("扣除学生课时失败 课程不存在", zap.Any("receiverMessage", m))
				continue
			}

			var student system.Student
			err = global.GVA_DB.Where("id=?", m.StudentID).First(&student).Error
			if err != nil {
				global.GVA_LOG.Error("扣除学生课时失败 学生不存在", zap.Any("receiverMessage", m))
				continue
			}
			//请假的学生不扣除课时
			var studentCourse system.StudentCourse
			err = global.GVA_DB.Where("student_id=?", m.StudentID).Where("teacher_course_id=?", m.CourseID).First(&studentCourse).Error
			if err != nil {
				global.GVA_LOG.Error("学生记录未找到", zap.Any("receiverMessage", m))
				continue
			}
			if studentCourse.Status == 3 {
				continue
			}

			var courseHourLog system.CourseHourLog
			courseHourLog.Type = teacherCourse.Classroom.Type
			courseHourLog.StudentID = student.ID
			courseHourLog.Change = -m.ClassCount
			courseHourLog.Explain = "学生上课扣除课时"
			courseHourLog.CreateTime = time.Now().Unix()
			if teacherCourse.Classroom.Type == 1 {
				student.SupUseTime += m.ClassCount
				courseHourLog.CurrentAllTime = student.SupAllTime
				courseHourLog.CurrentUseTime = student.SupUseTime
			} else {
				student.AccUseTime += m.ClassCount
				courseHourLog.CurrentAllTime = student.AccAllTime
				courseHourLog.CurrentUseTime = student.AccUseTime
			}
			err = global.GVA_DB.Transaction(func(tx *gorm.DB) error {
				if err := tx.Create(&courseHourLog).Error; err != nil {
					global.GVA_LOG.Error("扣除学生课时失败 数据库记录上课日志", zap.Any("receiverMessage", m))
					return err
				}

				if err := tx.Save(&student).Error; err != nil {
					global.GVA_LOG.Error("扣除学生课时失败 修改学生剩余课时失败", zap.Any("receiverMessage", m))
					return err
				}
				return nil
			})
			if err != nil {
				global.GVA_LOG.Error("扣除学生课时失败 修改学生剩余课时失败", zap.Any("receiverMessage", err.Error()))
			}
		}
	}()
	<-forever
}

func (st *StudentProcess) TestDelayPush() {
	//// 订阅学生在线状态
	//if token := global.GVA_MQTT.Subscribe("control/+/report", 0, onMessageReceived); token.Wait() && token.Error() != nil {
	//	log.Fatal(token.Error())
	//	return
	//}
	conn, _ := RabbitMQService.GetConnection()
	defer conn.Close()
	ch, err := conn.Channel()
	if err != nil {
		global.GVA_LOG.Info("recordStudentClasses Failed to open a channel", zap.Error(err))
		return
	}
	defer ch.Close()

	// 声明一个 delayed 类型的交换机
	err = ch.ExchangeDeclare(
		"delayed_exchange",  // name
		"x-delayed-message", // type
		true,                // durable
		false,               // auto-deleted
		false,               // internal
		false,               // no-wait
		amqp.Table{
			"x-delayed-type": "direct",
		},
	)
	if err != nil {
		global.GVA_LOG.Info("exchangeDeclare错误", zap.Error(err))
		return
	}

	// 声明一个队列
	q, err := ch.QueueDeclare(
		"delayed_queue", // name
		true,            // durable
		false,           // delete when unused
		false,           // exclusive
		false,           // no-wait
		nil,             // arguments
	)
	if err != nil {
		global.GVA_LOG.Info("Failed to declare a queue", zap.Error(err))
		return
	}

	// 绑定队列到交换机
	err = ch.QueueBind(
		q.Name,
		"routing_key",      // routing key
		"delayed_exchange", // exchange
		false,
		nil,
	)
	if err != nil {
		global.GVA_LOG.Info("Failed to bind a queue", zap.Error(err))
		return
	}

	// 发送带有延迟的消息
	body := "Hello, delayed message!"
	props := amqp.Table{
		"x-delay": 10000, // 延迟 5 秒
	}
	err = ch.Publish(
		"delayed_exchange", // exchange
		"routing_key",      // routing key
		false,              // mandatory
		false,              // immediate
		amqp.Publishing{
			ContentType:  "text/plain",
			Body:         []byte(body),
			Timestamp:    time.Now(),
			DeliveryMode: amqp.Persistent,
			Headers:      props,
		})
	if err != nil {
		global.GVA_LOG.Info("Failed to publish a message", zap.Error(err))
		return
	}
	log.Printf(" 发送延迟消息 Sent %s", body)
}
